﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Shrestha.Charts.Info;

namespace Shrestha.Charts
{
    public class Runner
    {
        private Stack<HistoryElement> _history;
        public bool ContainsMetaTable = false;
        public bool ContainsCharacters = false;
        public bool ContainsDescription = false;
        public bool ContainsGradient = false;

        public Legend legend { get; set; }
        
        private string _queryColumns;

        public string LatName, LngName, DateTimeName, CharacterName, Description, GradientName;
        public Metadata Meta;

        public DataSet BaseEvents;
        public DataSet BaseEventMetas;

        public Runner(DataSet Events, String latName, String lngName, String dateName, String characterName, String description)
        {
            this.BaseEvents = Events;
            this.LatName = latName;
            this.LngName = lngName;
            this.DateTimeName = dateName;

            _queryColumns = LatName + "," + LngName + "," + DateTimeName;

            if (characterName != null)
            {
                this.ContainsCharacters = true;
                this.CharacterName = characterName;
                _queryColumns += "," + CharacterName;
            }

            if (description != null)
            {
                this.ContainsDescription = true;
                this.Description = description;
                _queryColumns += Description;
            }

            Meta = new Metadata();
            this._history = new Stack<HistoryElement>();

            
        }

        public Runner(DataSet Events, String latName, String lngName, String dateName, String characterName, String description, String gradientName)
        {
            this.BaseEvents = Events;
            this.LatName = latName;
            this.LngName = lngName;
            this.DateTimeName = dateName;
            this.GradientName = gradientName;

            _queryColumns = LatName + "," + LngName + "," + DateTimeName;

            if (characterName != null)
            {
                this.ContainsCharacters = true;
                this.CharacterName = characterName;
                _queryColumns += "," + CharacterName;
            }

            if (description != null)
            {
                this.ContainsDescription = true;
                this.Description = description;
                _queryColumns += "," + Description;
            }

            if (gradientName != null)
            {
                this.ContainsGradient = true;
                this.GradientName = gradientName;
                _queryColumns += "," + GradientName;
            }

            Meta = new Metadata();
            this._history = new Stack<HistoryElement>();

        }

        public Runner(DataSet Events, DataSet Metas, String latName, String lngName, String dateName, String characterName, String description)
        {
            this.BaseEvents = Events;
            this.BaseEventMetas = Metas;
            this.ContainsMetaTable = true;

            this.LatName = latName;
            this.LngName = lngName;
            this.DateTimeName = dateName;

            _queryColumns = LatName + "," + LngName + "," + DateTimeName;

            if (characterName != null)
            {
                this.ContainsCharacters = true;
                this.CharacterName = characterName;
                _queryColumns += "," + CharacterName;
            }

            if (description != null)
            {
                this.ContainsDescription = true;
                this.Description = description;
                _queryColumns += Description;
            }
            Meta = new Metadata();
            this._history = new Stack<HistoryElement>();
        }

        public DataView GetCondition(String query)
        {
            DataView dv = null;
            _history.Push(new HistoryElement() { Query = query, Columns = _queryColumns });
            if(query==null ||query.Equals(""))
            dv = new DataView(BaseEvents.Tables[0], query, _queryColumns, DataViewRowState.CurrentRows);
            else
                dv = new DataView(BaseEvents.Tables[0], query, _queryColumns, DataViewRowState.CurrentRows);
            UpdateMeta(dv);
            return dv;
        }

        public DataView GetCondition(DataView qdv, String query)
        {
            DataView dv = null;
            _history.Push(new HistoryElement() { Query = query, Columns = _queryColumns });
            if (query == null || query.Equals(""))
                dv = new DataView(BaseEvents.Tables[0], query, _queryColumns, DataViewRowState.CurrentRows);
            else
                dv = new DataView(qdv.ToTable(), query, _queryColumns, DataViewRowState.CurrentRows);
            UpdateMeta(dv);
            return dv;
        }

        public DataView GetMetaAfterUpdate()
        {
            DataView dv = new DataView(BaseEventMetas.Tables[0], DateTimeName + " < '" + Meta.MaxEventDate + "' and " + DateTimeName + " > '" + Meta.MinEventDate+"'", DateTimeName, DataViewRowState.CurrentRows);
            return dv;
        }

        public DataView Undo()
        {
            DataView dv;
            if (_history.Count > 0)
            {
                HistoryElement he = _history.Pop();
                dv = new DataView(BaseEvents.Tables[0], he.Query, he.Columns, DataViewRowState.CurrentRows);
            }
            else
            {
                dv = new DataView(BaseEvents.Tables[0], "", _queryColumns, DataViewRowState.CurrentRows);
            }
            UpdateMeta(dv);
            return dv;
        }

        private void UpdateMeta(DataView dv)
        {
            if (dv.Count == 0) throw new RowNotInTableException();
            Meta.Update((double)dv.ToTable().Compute("max(" + LatName + ")", ""),
                (double)dv.ToTable().Compute("min(" + LatName + ")", ""),
                (double)dv.ToTable().Compute("max(" + LngName + ")", ""),
                (double)dv.ToTable().Compute("min(" + LngName + ")", ""),
                (DateTime)dv.ToTable().Compute("max(" + DateTimeName + ")", ""),
                (DateTime)dv.ToTable().Compute("min(" + DateTimeName + ")", "")
                );
        }

        
    }

    public class Metadata
    {
        public double MinLatitude;
        public double MaxLatitude;
        public double MinLongitude;
        public double MaxLongitude;
        public DateTime MinEventDate;
        public DateTime MaxEventDate;

        public void Update(double maxla, double minla, double maxlo, double minlo, DateTime maxd, DateTime mind)
        {
            MinLatitude = minla;
            MaxLatitude = maxla;
            MinLongitude = minlo;
            MaxLongitude = maxlo;
            MinEventDate = mind;
            MaxEventDate = maxd;
        }
    }
}
